#include "log.h"

#define LEVEL_NAME_LEN 8
#define LOG_BUF_LEN 4096

static int global_log_level = LEVEL_TRACE;


int set_log_level(int level) {
	global_log_level = level;
}


int get_level(const char *level_name) {
	if (strcmp("trace", level_name) == 0) {
		return LEVEL_TRACE;
	}
	if (strcmp("debug", level_name) == 0) {
		return LEVEL_DEBUG;
	}
	if (strcmp("info", level_name) == 0) {
		return LEVEL_INFO;
	}
	if (strcmp("warn", level_name) == 0) {
		return LEVEL_WARN;
	}
	if (strcmp("error", level_name) == 0) {
		return LEVEL_ERROR;
	}
	if (strcmp("fatal", level_name) == 0) {
		return LEVEL_FATAL;
	}
	if (strcmp("none", level_name) == 0) {
		return LEVEL_NONE;
	}
	return LEVEL_NONE;
}


inline static const char* level_name(int level) {
	switch (level) {
	case LEVEL_FATAL:
		return "[FATAL] ";
	case LEVEL_ERROR:
		return "[ERROR] ";
	case LEVEL_WARN:
		return "[WARN ] ";
	case LEVEL_INFO:
		return "[INFO ] ";
	case LEVEL_DEBUG:
		return "[DEBUG] ";
	case LEVEL_TRACE:
		return "[TRACE] ";
	}
	return "";
}


int logv(int level, const char *fmt, va_list ap) {
	char buf[LOG_BUF_LEN];
	int len;
	char *ptr = buf;
	len = sprintf(ptr, "%x ", pthread_self());
	if (len < 0) {
		return -1;
	}
	ptr += len;
	memcpy(ptr, level_name(level), LEVEL_NAME_LEN);
	ptr += LEVEL_NAME_LEN;
	int space = sizeof(buf) - (ptr - buf) - 2;
	len = vsnprintf(ptr, space, fmt, ap);
	if (len < 0) {
		return -1;
	}
	ptr += len > space ? space : len;
	*ptr++ = '\n';
	*ptr = '\0';
	len = ptr - buf;
	fwrite(buf, len, 1, stdout);
	// fflush(stdout);
	return len;
}


int log_write(int level, const char *fmt, ...) {
	if (global_log_level == LEVEL_NONE) {
		return 0;
	}
	if (level < global_log_level) {
		return 0;
	}
	va_list ap;
	va_start(ap, fmt);
	int ret = logv(level, fmt, ap);
	va_end(ap);
	return ret;
}

